package com.yilin.platform.base_core.tools.wechat;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.Verifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.cert.CertificatesManager;
import com.wechat.pay.contrib.apache.httpclient.exception.HttpCodeException;
import com.wechat.pay.contrib.apache.httpclient.exception.NotFoundException;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import com.yilin.platform.base_core.application.AppUtil;
import com.yilin.platform.base_core.commons.exception.BusinessException;

import java.io.*;
import java.lang.reflect.Type;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.util.Base64;

import com.yilin.platform.entity.user.deserialize.HatchWechat;
import okhttp3.HttpUrl;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;

import java.util.HashMap;
import java.util.Map;

public class WeChatUtils {
    static HttpUrl httpurl = HttpUrl.parse("https://api.mch.weixin.qq.com/v3/certificates");
    private static CloseableHttpClient httpClient;
    private static CertificatesManager certificatesManager;
    private static Verifier verifier;
    /*微信支付POSt请求*/
    public static Map<String, Object> weChatV3Post(HatchWechat hatchWechat, String userType, Map<String, Object> param, String url) {
        if (httpClient == null) setup(hatchWechat, userType);
        ObjectMapper objectMapper = new ObjectMapper();
        String paramJson = null;
        try {
            paramJson = objectMapper.writeValueAsString(param);
        } catch (JsonProcessingException e) {
            throw new BusinessException("微信请求Map转换失败！" + e.getMessage());
        }
        HttpPost httpPost = new HttpPost(url);
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type", "application/json; charset=utf-8");
        httpPost.setEntity(new StringEntity(paramJson, "UTF-8")); // 设置请求实体为 paramJson
        CloseableHttpResponse response;
        try {
            response = httpClient.execute(httpPost);
        } catch (IOException e) {
            throw new BusinessException("微信请求GET请求失败：" + e.getMessage());
        }
        return getResponse(response);
    }
    /*微信支付GEt请求*/
    public static Map<String, Object> weChatV3Get(HatchWechat hatchWechat, String userType, String url) {

        if (httpClient == null) setup(hatchWechat, userType);
        HttpGet httpGet = new HttpGet(url);
        httpGet.addHeader("Accept", "application/json");
        httpGet.addHeader("Content-type", "application/json; charset=utf-8");
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpGet);
        } catch (IOException e) {
            throw new BusinessException("微信请求GET请求失败：" + e.getMessage());
        }
        return getResponse(response);
    }

    /*微信支付GEt下载请求*/
    public static Map<String, Object> weChatV3GetDown(HatchWechat hatchWechat, String userType, String url) {
        // 假设这是你的请求参数
        if (httpClient == null) setup(hatchWechat, userType);
        String mchid = hatchWechat.getMchId(userType);
        String nonce_str = AppUtil.getUUID();
        String timestamp = System.currentTimeMillis()/1000+"";
        String serial_no = hatchWechat.getSerialNo(userType);
        String privateKeyFilePath = hatchWechat.getPrivateKeyUrl(userType);
        // 生成签名
        String signature = getSign(nonce_str, timestamp, url, privateKeyFilePath,"GET");
        // 组装Authorization头部值
        String authorizationHeader = "WECHATPAY2-SHA256-RSA2048 mchid=\"" + mchid + "\", " +
                "nonce_str=\"" + nonce_str + "\", " +
                "signature=\"" + signature + "\", " +
                "timestamp=\"" + timestamp + "\", " +
                "serial_no=\"" + serial_no + "\"";
        // 发起HTTP请求
        HttpGet httpGet = new HttpGet(url);
        httpGet.addHeader("Authorization", authorizationHeader);
        CloseableHttpResponse response = null;
        try {
            response = httpClient.execute(httpGet);
        } catch (IOException e) {
            throw new BusinessException("微信请求GET请求失败：" + e.getMessage());
        }
        return getResponse(response);
    }


    //    获取帧数
    private static void setup(HatchWechat hatchWechat, String userType) {
        try {
            String mchId =hatchWechat.getMchId(userType);
            String serialNo = hatchWechat.getSerialNo(userType);
            String privateKeyFilePath =  hatchWechat.getPrivateKeyUrl(userType);
            String apiV3Key =  hatchWechat.getApiV3Key(userType);
            byte[] privateKeyBytes = Files.readAllBytes(Paths.get(privateKeyFilePath));
            PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKeyBytes));
            certificatesManager = CertificatesManager.getInstance();
            certificatesManager.putMerchant(mchId, new WechatPay2Credentials(mchId, new PrivateKeySigner(serialNo, merchantPrivateKey)), apiV3Key.getBytes(StandardCharsets.UTF_8));
            verifier = certificatesManager.getVerifier(mchId);
            httpClient = WechatPayHttpClientBuilder.create().withMerchant(mchId, serialNo, merchantPrivateKey).withValidator(new WechatPay2Validator(certificatesManager.getVerifier(mchId))).build();
        } catch (IOException | NotFoundException | HttpCodeException | GeneralSecurityException e) {
            e.printStackTrace();
        }
    }

    // 请求返回处理
    private static Map<String, Object> getResponse(CloseableHttpResponse response) {
        try {
            int statusCode = response.getStatusLine().getStatusCode();
            Map<String, Object> map = new HashMap<>();
            if (statusCode == 200) {
                HttpEntity entity = response.getEntity();
                if (entity != null) {
                    Gson gson = new Gson();
                    Type type = new TypeToken<Map<String, Object>>() {
                    }.getType();
                    map = gson.fromJson(EntityUtils.toString(entity, "UTF-8"), type);
                }
                return map;
            } else {
                throw new BusinessException("微信请求失败,请求失败码:" + statusCode);
            }
        } catch (IOException e) {
            throw new BusinessException("微信请求失败,失败信息" + e.getMessage());
        }
    }

    //##############################################内部方法#########################################################
    public static String getSign(String nonceStr, String timestamp, String body, String privateKey,String method) {
        String message = buildMessage(method, httpurl, timestamp, nonceStr, body);
        return sign(message.getBytes(StandardCharsets.UTF_8), privateKey);
    }

    private static String sign(byte[] message, String privateKey) {
        try {
            byte[] privateKeyBytes = Files.readAllBytes(Paths.get(privateKey));
            PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(privateKeyBytes));
            Signature sign = Signature.getInstance("SHA256withRSA");
            sign.initSign(merchantPrivateKey);
            sign.update(message);
            return Base64.getEncoder().encodeToString(sign.sign());
        } catch (NoSuchAlgorithmException | IOException | SignatureException | InvalidKeyException e) {
            e.printStackTrace();
        }
        return null;
    }
    private static String buildMessage(String method, HttpUrl url, String timestamp, String nonceStr, String body) {
        String canonicalUrl = url.encodedPath();
        if (url.encodedQuery() != null) {
            canonicalUrl += "?" + url.encodedQuery();
        }
        return method + "\n"
                + canonicalUrl + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }

}
